/*
 *****************************************************************************
 ** Module	:	com.hp.bon.sc.utils
 ** Date: 2009-10-15				Time: 15:45:35
 ** Author: Wang Bo (Brain Wang)  2009
 *****************************************************************************
 ********************* CVS Change History ************************************
 * $Id: DccMessageBuilder.java,v 1.7 2012/09/28 02:50:00 sunhy Exp $
 * $Log: DccMessageBuilder.java,v $
 * Revision 1.7  2012/09/28 02:50:00  sunhy
 * *** empty log message ***
 *
 * Revision 1.6  2012/09/06 02:53:25  sunhy
 * *** empty log message ***
 *
 * Revision 1.5  2012/09/06 02:53:11  sunhy
 * *** empty log message ***
 *
 * Revision 1.4  2012/09/04 05:15:05  sunhy
 * *** empty log message ***
 *
 * Revision 1.3  2012/08/31 09:54:29  sunhy
 * *** empty log message ***
 *
 * Revision 1.2  2012/08/31 04:43:18  sunhy
 * *** empty log message ***
 *
 * Revision 1.1  2012/06/20 03:25:35  sunhy
 * *** empty log message ***
 *
 * Revision 1.5  2012/06/07 02:27:32  sunhy
 * *** empty log message ***
 *
 * Revision 1.4  2011/10/24 11:45:57  wangph
 * *** empty log message ***
 *
 * Revision 1.3  2011/10/21 04:38:34  sunhy
 * M 比特修改
 *
 * Revision 1.2  2011/10/11 00:19:14  sunhy
 * *** empty log message ***
 *
 * Revision 1.1  2011/09/07 02:21:03  sunhy
 * *** empty log message ***
 *
 * Revision 1.6  2011/09/06 05:16:05  sunhy
 * *** empty log message ***
 *
 * Revision 1.5  2011/09/05 03:05:33  sunhy
 * *** empty log message ***
 *
 * Revision 1.4  2011/09/01 05:56:17  sunhy
 * *** empty log message ***
 *
 * Revision 1.3  2011/08/19 08:22:06  sunhy
 * *** empty log message ***
 *
 * Revision 1.2  2011/08/12 03:35:56  sunhy
 * *** empty log message ***
 *
 * Revision 1.1  2011/08/09 09:48:04  sunhy
 * *** empty log message ***
 *
 * Revision 1.5  2011/07/20 09:15:57  sunhy
 * *** empty log message ***
 *
 * Revision 1.4  2011/06/24 06:30:41  sunhy
 *
 * Revision 1.3  2011/06/23 09:52:39  sunhy
 * *** empty log message ***
 *
 * Revision 1.2  2011/06/23 08:38:14  sunhy
 * *** empty log message ***
 *
 * Revision 1.1  2011/06/22 06:16:33  sunhy
 * *** empty log message ***
 *
 * Revision 1.2  2011/04/14 08:01:09  licz
 * *** empty log message ***
 *
 * Revision 1.1  2011/04/13 09:27:49  licz
 * created by lichangzhen 20110413
 *
 *****************************************************************************
 */
package com.hp.bon.sgw.util.dcc;

import static com.hp.ocs.diameter.ProtocolConstants.DIAMETER_APPLICATION_CREDIT_CONTROL;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.Constants;
import com.hp.ocs.diameter.message.AVP;
import com.hp.ocs.diameter.message.AVP_Grouped;
import com.hp.ocs.diameter.message.AVP_Unsigned32;
import com.hp.ocs.diameter.message.DictionaryManager;
import com.hp.ocs.diameter.message.Message;
import com.hp.ocs.diameter.message.dictionary.Avp;

/**
 */
@Path("/")
public class DccMessageBuilder {

	private static Logger _log = LoggerFactory.getLogger(DccMessageBuilder.class);
	private volatile Map<String, MessageDef> _mapMessageId2MsgAvpDef = new HashMap<String, MessageDef>();
	private File _caseConfig;
	private static DictionaryManager _dic = DictionaryManager.getInstance();
	private final static Map<String, Integer> _mapMessageType2Code = new HashMap<String, Integer>();
	static {
		_mapMessageType2Code.put("CCR", 272);
		_mapMessageType2Code.put("CCA", -272);
	}

	public DccMessageBuilder(String xmlFile) {
		_caseConfig = new File(xmlFile);
		reloadDccMessageConfig();
	}

	@GET
	@Path("config/reloadmsgbuilder")
	@Produces(MediaType.TEXT_PLAIN)
	public String reloadDccMessageConfig() {
		String result = "SUCCESS ";

		_log.info("Loading DCC Message ConfigFile " + _caseConfig);
		try {
			SAXReader reader = new SAXReader();
			Document doc = reader.read(_caseConfig);
			Element eCaseConfig = doc.getRootElement();
			configure(eCaseConfig);
			_log.info("Loaded Case " + _caseConfig);
		} catch (Exception e) {
			result = "ERR:" + e;
			_log.warn("Configuring Case error", e);
		}
		return result;
	}

	public MessageDef getMessageDef(String msgID) {
		return _mapMessageId2MsgAvpDef.get(msgID);
	}

	public List<String> findCCAMsgIDsOfSCID(String scid) {
		List<String> result = new LinkedList<String>();
		for (MessageDef msgDef : _mapMessageId2MsgAvpDef.values()) {
			if (scid.equals(msgDef.getScid()) && msgDef.getType().equalsIgnoreCase("CCA")) {
				result.add(msgDef.getId());
			}
		}
		return result;
	}

	public MessageDef findCCAForSCID(String scid) {
		for (MessageDef msgDef : _mapMessageId2MsgAvpDef.values()) {
			if (scid.equals(msgDef.getScid()) && msgDef.getType().equalsIgnoreCase("CCA")) {
				return msgDef;
			}
		}
		return null;
	}

	private String[] allCCRMessage;

	public String[] getAllCCR() {
		return allCCRMessage;
	}

	public MessageDef findMessageDef(String scid) {
		for (MessageDef msgDef : _mapMessageId2MsgAvpDef.values()) {
			if (scid.equals(msgDef.getScid())) {
				return msgDef;
			}
		}
		return null;
	}

	/**
	 * 读取xml文件对应msgId的消息模板，生成Diameter消息
	 * 
	 * @param msgId
	 *            Message template ID
	 * @param msgVars
	 *            Message template vars
	 * @return 消息，null表示失败
	 */
	public static Message buildMessage(Message message, MessageDef eFormat, Properties msgVars) {

		message.header().setProxiable(true);
		message.header().setApplicationID(DIAMETER_APPLICATION_CREDIT_CONTROL);
		// make AVPs

		// MessageDef eFormat = _mapMessageId2MsgAvpDef.get(msgId);

		if (null == eFormat) {
			AVP avpServiceResultCode = new AVP_Unsigned32(Constants.DIAMETER_AVP_SERVICE_RESULT_CODE, Constants.DIAMETER_VENDOR_CT, Constants.DIAMETER_RESULT_UNABLE_TO_COMPLY);

			avpServiceResultCode.setMandatory(true);
			AVP_Grouped avpServiceInfomaiton = new AVP_Grouped(Constants.DIAMETER_AVP_SERVICE_INFOMATION, Constants.DIAMETER_VENDOR_3GPP, new AVP[] { avpServiceResultCode });
			avpServiceInfomaiton.setMandatory(true);
			message.add(avpServiceInfomaiton);

		} else {
			Integer msgCode = _mapMessageType2Code.get(eFormat.getType());
			if (msgCode == null)
				throw new IllegalArgumentException("unsupported message type " + eFormat.getType());
			if (msgCode > 0) {
				message.header().setRequest(true);
				message.header().setCommandCode(msgCode);
			} else {
				msgCode = -msgCode;
				message.header().setRequest(false);
				message.header().setCommandCode(msgCode);
			}
			for (Object o : eFormat.getAvps()) {
				AvpDef eAVP = (AvpDef) o;
				AVP avp = makeAVP(eAVP, msgVars);
				message.add(avp);
			}
		}
		return message;
	}

	@SuppressWarnings("rawtypes")
	private static AVP makeAVP(AvpDef eAVP, Properties msgVars) {
		String name = eAVP.getName();

		if (eAVP.getAvps() != null) {
			Iterator i = eAVP.getAvps().iterator();
			if (i.hasNext()) {
				// Group AVP
				List<AVP> subavps = new ArrayList<AVP>();
				while (i.hasNext()) {
					AvpDef eSubAVP = (AvpDef) i.next();
					subavps.add(makeAVP(eSubAVP, msgVars));
				}
				return _dic.makeAVP(DIAMETER_APPLICATION_CREDIT_CONTROL, name, subavps.toArray(new AVP[subavps.size()]));
			}
		}
		// Single AVP
		String value = eAVP.getValue();
		if (value != null) {
			int idx = value.indexOf("${");
			if (idx >= 0) {
				int idx1 = value.indexOf('}', idx);
				String varKey = value.substring(idx + 2, idx1);
				String varValue = msgVars.getProperty(varKey);
				StringBuilder sb = new StringBuilder();
				if (idx > 0) {
					sb.append(value.substring(0, idx));
				}
				if (varValue != null) {
					sb.append(varValue);
				}
				if (idx1 + 1 < value.length()) {
					sb.append(value.substring(idx1 + 1));
				}
				value = sb.toString();
			}
		}
		if(value != null && eAVP.getValue().equals(value) && eAVP.getAvpObject() != null)
		{
			return eAVP.getAvpObject();
		}		
		eAVP.setAvpObject(_dic.makeAVP(DIAMETER_APPLICATION_CREDIT_CONTROL, name, value));
		return eAVP.getAvpObject();
	}

	@SuppressWarnings("unused")
	private AVP getPropertyAVP(String name, String propName, Properties props) {
		String value = props.getProperty(propName);
		if (value == null)
			throw new IllegalArgumentException("Unsupport property " + propName + " while making AVP " + name);
		return _dic.makeAVP(DIAMETER_APPLICATION_CREDIT_CONTROL, name, value);
	}

	@SuppressWarnings("rawtypes")
	private void configure(Element xmlCase) throws IllegalArgumentException {
		HashMap<String, MessageDef> msgId2MsgAvpDef = new HashMap<String, MessageDef>();
		// Message
		ArrayList<String> allCCR = new ArrayList<String>();
		for (Iterator i = xmlCase.elementIterator("Message"); i.hasNext();) {
			Element eMessage = (Element) i.next();
			String id = eMessage.attributeValue("id");
			MessageDef msgDef = makeMessageDef(eMessage);
			msgId2MsgAvpDef.put(id, msgDef);
			if (msgDef.getType().equalsIgnoreCase("CCR")) {
				allCCR.add(msgDef.getId());
			}
		}
		allCCRMessage = new String[allCCR.size()];
		allCCR.toArray(allCCRMessage);
		this._mapMessageId2MsgAvpDef = msgId2MsgAvpDef;
	}

	@SuppressWarnings("rawtypes")
	public static MessageDef makeMessageDef(Element eMessage) {
		MessageDef messageDef = new MessageDef();
		String id = eMessage.attributeValue("id");
		String type = eMessage.attributeValue("type");
		String scid = eMessage.attributeValue("scid");
		messageDef.setId(id);
		messageDef.setType(type);
		messageDef.setScid(scid);
		messageDef.beforeRespScript = eMessage.elementText("before-response-script");;
		List<AvpDef> avps = new ArrayList<AvpDef>();
		for (Iterator i = eMessage.elementIterator("AVP"); i.hasNext();) {
			Element eAVP = (Element) i.next();
			AvpDef avp = makeAvpDef(eAVP);
			avps.add(avp);
		}
		messageDef.setAvps(avps);
		return messageDef;
	}

	@SuppressWarnings("rawtypes")
	private static AvpDef makeAvpDef(Element eAVP) {
		AvpDef avpDef = new AvpDef();
		String name = eAVP.attributeValue("name");
		String value = eAVP.attributeValue("value");
		avpDef.setName(name);
		avpDef.setValue(value);
		Iterator i = eAVP.elementIterator("AVP");
		if (i.hasNext()) {
			// Group AVP
			List<AvpDef> subavps = new ArrayList<AvpDef>();
			while (i.hasNext()) {
				Element eSubAVP = (Element) i.next();
				subavps.add(makeAvpDef(eSubAVP));
			}
			avpDef.setAvps(subavps);
			return avpDef;
		}
		// Single AVP
		return avpDef;
	}

	public String getAvpName(AVP avp) {
		Avp type = _dic.findAvpType(DIAMETER_APPLICATION_CREDIT_CONTROL, avp.code(), avp.vendorID());
		if (type == null)
			return "UnknownAVP:" + avp.vendorID() + "." + avp.code();
		return type.getName();
	}

	public static void main(String[] args) throws IOException {
		// DccMessageBuilder builder = new DccMessageBuilder(
		// "./test/message-config.xml");
		Message message = new Message();
		// Properties vars0 = new Properties();
		// builder.buildMessage(message, "RatableResourceQuery.CCA", vars0);
		System.out.println(message.getDictionary().toString());
	}
}
